﻿using B.S.BaseData.ErrorCode;
using B.S.BaseData.Infrastructure.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace B.S.BaseData.Infrastructure.Implements
{
    public class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        private readonly BaseDbContext _db;
        readonly ILogger<BaseRepository<T>> _logger;

        public BaseRepository(BaseDbContext db, ILogger<BaseRepository<T>> logger)
        {
            this._db = db;
            this._logger = logger;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> AddAsync(T entity)
        {
            try
            {
                await _db.Set<T>().AddAsync(entity);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("添加出错" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="tlist"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> AddRangeAsync(IList<T> tlist)
        {
            try
            {
                await _db.Set<T>().AddRangeAsync(tlist);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("添加出错" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(T info)
        {
            try
            {
                 _db.Remove(info);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("删除出错" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="tlist"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> DeleteRangeAsync(IList<T> tlist)
        {
            try
            {
                 _db.Set<T>().RemoveRange(tlist);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("批量删除出错" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// int编号查询
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<T?> GetByIdAsync(int id)
        {
            try
            {
                return await _db.Set<T>().FindAsync(id);
            }
            catch (Exception ex)
            {
                // 写异常日志
                _logger.LogError("根据id查询出错！" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 显示
        /// </summary>
        /// <returns></returns>
        public IQueryable<T> GetAll()
        {
            try
            {
                return _db.Set<T>().AsQueryable();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("返回所有列表信息出错" + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 单条件查询
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<T?> GetAsync(Expression<Func<T, bool>> expression)
        {
            try
            {
                return await _db.Set<T>().Where(expression).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("反填出错" + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 反填ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<T?> GetByIdAsync(long id)
        {
            try
            {
                return await _db.Set<T>().FindAsync(id);
            }
            catch (Exception ex)
            {
                // 写异常日志
                _logger.LogError("反填出错！" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<ApiPaging<T>> GetPageListAsync(int pageIndex, int pageSize, Expression<Func<T, bool>>? expression = null)
        {
            try
            {
                IQueryable<T> query = _db.Set<T>();

                //int count = await query.CountAsync();

                if (expression != null)
                {
                    query = query.Where(expression);
                }

                //分页
                int TotalCount = await query.CountAsync();
                int TotalPage = (int)Math.Ceiling(TotalCount * 1.0 / pageSize);

                //数据
                var data = await query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();

                return new ApiPaging<T>(TotalCount, TotalPage, data);
            }
            catch (Exception ex)
            {
                _logger.LogError("分页出错！" + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> UpdateAsync(T entity)
        {
            try
            {
                _db.Set<T>().Update(entity);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("修改出错" + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 批量修改
        /// </summary>
        /// <param name="tlist"></param>
        /// <returns></returns>
        public async Task<int> UpdateRangeAsync(IList<T> tlist)
        {
            try
            {
                _db.Set<T>().UpdateRange(tlist);
                return await _db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                //写异常日志
                _logger.LogError("批量出错" + ex.Message);
                throw;
            }
        }
        /// <summary>
        /// 导出
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="sheetName"></param>
        /// <returns></returns>
        public byte[] ExportToExcelMy<T>(List<T> data, string sheetName = "Sheet1")
        {
            // 1. 创建一个新的 Excel 工作簿，这里使用 XSSFWorkbook 表示 .xlsx 格式
            var workbook = new XSSFWorkbook();
            // 2. 在工作簿中创建一个新的工作表，并指定其名称
            var sheet = workbook.CreateSheet(sheetName);

            #region 创建标题行样式
            // 创建一个单元格样式对象，用于设置表头的样式
            var headerStyle = workbook.CreateCellStyle();
            // 创建一个字体对象，用于设置表头文本的字体
            var headerFont = workbook.CreateFont();
            // 设置表头字体大小为 12 
            headerFont.FontHeightInPoints = 12;
            // 设置表头字体加粗
            headerFont.IsBold = true;
            // 将字体应用到表头样式
            headerStyle.SetFont(headerFont);
            // 设置表头文本水平居中对齐
            headerStyle.Alignment = HorizontalAlignment.Center;
            // 设置表头文本垂直居中对齐
            headerStyle.VerticalAlignment = VerticalAlignment.Center;
            // 设置表头单元格的背景填充前景色为 25% 灰色
            headerStyle.FillForegroundColor = IndexedColors.Grey25Percent.Index;
            // 设置表头单元格的填充模式为纯色填充
            headerStyle.FillPattern = FillPattern.SolidForeground;
            // 设置表头单元格上边框为细线
            headerStyle.BorderTop = BorderStyle.Thin;
            // 设置表头单元格下边框为细线
            headerStyle.BorderBottom = BorderStyle.Thin;
            // 设置表头单元格左边框为细线
            headerStyle.BorderLeft = BorderStyle.Thin;
            // 设置表头单元格右边框为细线
            headerStyle.BorderRight = BorderStyle.Thin;
            #endregion

            #region 创建内容样式
            // 创建一个单元格样式对象，用于设置内容区域的样式
            var contentStyle = workbook.CreateCellStyle();
            // 创建一个字体对象，用于设置内容文本的字体
            var contentFont = workbook.CreateFont();
            // 设置内容字体大小为 11 磅
            contentFont.FontHeightInPoints = 11;
            // 将字体应用到内容样式
            contentStyle.SetFont(contentFont);
            // 设置内容文本水平左对齐
            contentStyle.Alignment = HorizontalAlignment.Left;
            // 设置内容文本垂直居中对齐
            contentStyle.VerticalAlignment = VerticalAlignment.Center;
            // 设置内容单元格上边框为细线
            contentStyle.BorderTop = BorderStyle.Thin;
            // 设置内容单元格下边框为细线
            contentStyle.BorderBottom = BorderStyle.Thin;
            // 设置内容单元格左边框为细线
            contentStyle.BorderLeft = BorderStyle.Thin;
            // 设置内容单元格右边框为细线
            contentStyle.BorderRight = BorderStyle.Thin;
            #endregion

            // 获取类型 T 的所有公共属性，并过滤掉在 excludeProperties 列表中指定的属性
            var properties = typeof(T).GetProperties().ToList();
            /*.Where(p => excludeProperties == null || !excludeProperties.Contains(p.Name))*/


            // 创建第一行（索引为 0）作为表头行
            var headerRow = sheet.CreateRow(0);
            // 设置表头行高，单位是 twip（1 twip = 1/20 磅），400 twip = 20 磅
            headerRow.Height = 400;
            // 遍历所有要导出的属性，创建表头单元格
            for (int i = 0; i < properties.Count; i++)
            {
                // 在当前表头行创建第 i 个单元格
                var cell = headerRow.CreateCell(i);
                // 获取属性的 DisplayName 特性值，如果不存在则使用属性本身的名称作为列名
                var displayName = properties[i].GetCustomAttribute<DisplayNameAttribute>()?.DisplayName
                    ?? properties[i].Name;
                // 设置单元格的值为显示名称
                cell.SetCellValue(displayName);
                // 将之前定义的表头样式应用到当前单元格
                cell.CellStyle = headerStyle;
            }

            // 初始化行索引，从第二行（索引为 1）开始填充数据
            int rowIndex = 1;
            // 遍历数据列表中的每一个数据项
            foreach (var item in data)
            {
                // 在当前工作表创建新的数据行
                var row = sheet.CreateRow(rowIndex);
                // 设置数据行高，单位是 twip，350 twip = 17.5 磅
                row.Height = 350;

                // 遍历当前数据项的所有属性，填充单元格数据
                for (int i = 0; i < properties.Count; i++)
                {
                    // 在当前数据行创建第 i 个单元格
                    var cell = row.CreateCell(i);
                    // 获取当前属性在当前数据项中的值
                    var value = properties[i].GetValue(item);

                    // 根据属性类型设置单元格的值，以确保正确的格式
                    if (value != null) // 确保值不为空
                    {
                        // 如果是 DateTime 或可空的 DateTime 类型
                        if (properties[i].PropertyType == typeof(DateTime) ||
                            properties[i].PropertyType == typeof(DateTime?))
                        {
                            // 将日期时间格式化为 "yyyy-MM-dd HH:mm:ss" 字符串
                            cell.SetCellValue(((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"));
                        }
                        // 如果是 bool 或可空的 bool 类型
                        else if (properties[i].PropertyType == typeof(bool) ||
                                 properties[i].PropertyType == typeof(bool?))
                        {
                            // 根据布尔值设置为 "是" 或 "否"
                            cell.SetCellValue((bool)value ? "是" : "否");
                        }
                        // 如果是枚举类型
                        else if (properties[i].PropertyType.IsEnum)
                        {
                            // 获取枚举值的名称（字符串形式）
                            cell.SetCellValue(Enum.GetName(properties[i].PropertyType, value));
                        }
                        // 对于其他所有类型
                        else
                        {
                            // 将值转换为字符串设置到单元格
                            cell.SetCellValue(value.ToString());
                        }
                    }
                    // 将之前定义的内容样式应用到当前单元格
                    cell.CellStyle = contentStyle;
                }
                // 行索引递增，准备处理下一行数据
                rowIndex++;
            }

            // 遍历所有列，自动调整列宽并设置最小/最大限制
            for (int i = 0; i < properties.Count; i++)
            {
                // 自动调整当前列的宽度以适应其内容
                sheet.AutoSizeColumn(i);
                // 设置最小列宽：如果自动调整后的宽度小于 15 个字符宽（15 * 256 twip），则设置为 15 个字符宽
                if (sheet.GetColumnWidth(i) < 15 * 256)
                {
                    sheet.SetColumnWidth(i, 15 * 256);
                }
                // 设置最大列宽：如果自动调整后的宽度大于 50 个字符宽（50 * 256 twip），则限制为 50 个字符宽
                if (sheet.GetColumnWidth(i) > 50 * 256)
                {
                    sheet.SetColumnWidth(i, 50 * 256);
                }
            }

            // 使用 MemoryStream 将工作簿内容写入内存
            using (var ms = new MemoryStream())
            {
                // 将整个工作簿的数据写入内存流
                workbook.Write(ms);
                // 将内存流中的数据转换为字节数组并返回
                return ms.ToArray();
            }
        }



    }
}
